Repository navigation
fix(response-viewer): a session on a relocated Claude config folder gets its answers back - #812
Merged
Merged
Conversation
…ets its answers back (#701) The viewer looked for a Claude transcript under ~/.claude/projects only, and for the conversation after a /clear in ~/.claude/history.jsonl only. A session started with its own CLAUDE_CONFIG_DIR (a second account, #255), or any session on a server that exports one, writes both elsewhere, so the eye button showed "No response yet" or a terminal dump, and codeman agent read and the Discord bridge's last message came back empty. This is the third part of the report in issue 701; the other two are a design choice and a feature request. lastResponseFor() now asks claudeConversationDirs() for the folder the session's claude writes to: its own override, then the server's, then ~/.claude, through claudeProjectsDir(), which the relaunch pin and the Edit history panel already use. The rename's /resume title takes the same lookup when no hook has named the transcript yet. - Local sessions only. In a Docker case or on a remote host the override names a folder over there, and the same path on this host is someone else's. - A relocated folder is a path somebody chose, so it is probed bounded first (the rule from issue 516). Anything but a directory reads as no transcript, never as a reason to look under ~/.claude, where a file of the same name is another account's conversation. - The default folder is not probed, so that path is as before. Not changed: the resume pre-validation at session create and the host-wide history scans still read the default folder. Tests: five route cases for the viewer (own folder, the server's, no fallback, /clear through the relocated history, Docker left alone) and one for the rename. Each part of the change fails one of them when reverted. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A Claude session can run on its own Claude config folder. Codeman supports that through the session environment override
CLAUDE_CONFIG_DIR, which is how one machine runs one session on a second Claude account, and a server can also export the variable for every session it starts. Claude then keeps its transcripts and itshistory.jsonlunder that folder instead of~/.claude.The response viewer (the eye button,
GET /api/sessions/:id/last-response) looked under~/.claudeonly. For such a session:/clearthe viewer stayed on the old conversation, because the history file it follows was read from~/.claudetoo,/resumetitle until a hook had named the transcript.The Edit history panel and the relaunch pin already resolve the right folder. The viewer did not.
This is the third part of issue #701 ("a transcript outside
~/.claude/projectscan also be missed"). The other two parts of that issue are not in this PR, so it stays open.Change
One helper,
claudeConversationDirs(session)insrc/web/routes/session-routes.ts, answers where this session's Claude keeps its conversations:<config dir>/projectsand<config dir>/history.jsonl. It resolves the folder throughclaudeProjectsDir(), the function the relaunch pin and the Edit history panel use: the session's own override first, then the server'sCLAUDE_CONFIG_DIR, then~/.claude.lastResponseFor()(the viewer route and the Discord bridge) takes both paths from it.resolveActiveClaudeSessionIdFromHistory()gets the history path as a parameter instead of building~/.claude/history.jsonlitself.syncClaudeTitle()(the rename's/resumetitle) uses the same lookup when no hook has named the transcript yet.Three rules live in the helper:
~/.claude. A file of the same name there is another account's conversation.The default folder is not probed, so a session without any override takes the path it took before.
Docs: the root
CLAUDE.md,docs/architecture-invariants.mdand the wiki pages Agent CLIs and Watching Agents Work no longer list the response viewer among the surfaces that go blind on a relocated folder.Not in this PR
resumeSessionIdhas a transcript (validatedResumeIdin the same file) still reads~/.claude/projectsonly, so a resume on a relocated folder is likely dropped there. That is a follow-up./clearor a resume (a feature request, undecided).Reviewing the diff
One source file. Read
claudeConversationDirs()first, then its three call sites. The rest of the diff is tests and four doc files.Risk
CLAUDE_CONFIG_DIRnow has the viewer read that folder for every local Claude session. That is the point of the change, and it is a behaviour change for such a server.homedir()now, where the old line readprocess.env.HOMEwith/tmpas a fallback. Both give the same folder wheneverHOMEis set.CLAUDE_CONFIG_DIRis already a privileged key there (only an admin may set it), so the viewer reads no folder a non-admin could choose.Verification
test/routes/session-routes-claude-last-response.test.ts(the session's own folder, the server's, no fallback to~/.claude, a/clearfollowed through the relocated history, a Docker session left alone) and one for the rename intest/routes/session-name-routes.test.ts.check:lockfile,typecheck,lint,check:frontend-syntax,check:browser-excludes,format:check,check:public-assetsand the CLI catalogue check pass.npm test: 756 files and 17,120 tests passed, none failed.last-responsealso pass on a machine that exportsCLAUDE_CONFIG_DIR(91 of 91; the test setup clears it).POST /api/sessions:envOverrides.CLAUDE_CONFIG_DIRset, and a one-line transcript under that folder: the brief and the full read both return its text,200with an empty text.Not verified: a real Claude process writing into a relocated folder end to end. The live read used a hand-written one-line transcript. Docker and remote sessions are covered by the unit test only (they must stay on the old lookup).
No changeset: the next release's changeset names this change.
Part of #701.